/***************************************************************************
 *   Copyright (C) 2006 by Yuri Ovcharenko                                 *
 *   amwsoft@gmail.com                                                     *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "console.h"

#include <QtGui>

Console::Console(QWidget *parent)
  : QFrame(parent)
{
  QAction *act;

  clear();
  setFont(QFont("Fixed", 10));

  setFrameStyle(QFrame::Box | QFrame::Sunken);
  QPalette p = palette();
  p.setColor(QPalette::Window, QColor(255, 255, 255));
  setPalette(p);

  setFocusPolicy(Qt::StrongFocus);

  setConsoleSize(80, 25);

  act = new QAction(tr("Copy"), this);
  connect(act, SIGNAL(triggered()), this, SLOT(copy()));
  addAction(act);

  act = new QAction(tr("Paste"), this);
  connect(act, SIGNAL(triggered()), this, SLOT(paste()));
  addAction(act);

  act = new QAction(this);
  act->setSeparator(true);
  addAction(act);

  act = new QAction(tr("Clear"), this);
  connect(act, SIGNAL(triggered()), this, SLOT(clear()));
  addAction(act);

  act = new QAction(this);
  act->setSeparator(true);
  addAction(act);

  act = new QAction(tr("Show font metrics"), this);
  connect(act, SIGNAL(triggered()), this, SLOT(slotShowFontMetrics()));
  addAction(act);

  act = new QAction(tr("Show geometry"), this);
  connect(act, SIGNAL(triggered()), this, SLOT(slotShowGeometry()));
  addAction(act);

  /* Right Mouse Click display Console's actions */
  setContextMenuPolicy(Qt::ActionsContextMenu);
}

Console::~Console()
{
}

/*----------------------------------------------------------------------------*/
QSize Console::sizeHint() const
{
  QFontMetrics fm(fontMetrics());
  int ww, hh;
  ww = fm.maxWidth();
  hh = fm.height();

  return QSize(ConsoleSize.width() * ww + ww + frameWidth() * 2, ConsoleSize.height() * hh + hh + frameWidth() * 2);
}

QSize Console::minimumSizeHint() const
{
  QFontMetrics fm(fontMetrics());
  int ww, hh;
  ww = fm.maxWidth();
  hh = fm.height();

  return QSize(ConsoleSize.width() * ww + ww + frameWidth() * 2, ConsoleSize.height() * hh + hh + frameWidth() * 2);
}

/*----------------------------------------------------------------------------*/
void Console::setConsoleSize(const QSize & sz)
{
  setConsoleSize(sz.width(), sz.height());
}

void Console::setConsoleSize(const int w, const int h)
{
  int ww = (w < 2 ? 2 : w);
  int hh = (h < 2 ? 2 : h);

  ConsoleSize.setWidth(ww);
  ConsoleSize.setHeight(hh);

  QFontMetrics fm(fontMetrics());
  ww = fm.maxWidth();
  hh = fm.height();

  QSize sz(QSize(ConsoleSize.width() * ww + ww + frameWidth() * 2, ConsoleSize.height() * hh + hh + frameWidth() * 2));
  setMinimumSize(sz);
  resize(sz);
}

QSize Console::consoleSize()
{
  return QSize(ConsoleSize);
}

void Console::setConsoleFont(const QFont & fnt)
{
  setFont(fnt);
  setConsoleSize(consoleSize());
  clear();
}

/*----------------------------------------------------------------------------*/
void Console::append(const QString & text)
{
  QString s;
  int t;

  if (Text.size() < 1)
  {
    Text.append(QString());
    xPos = 0;
  }
  for (int i = 0; i < text.size(); i++)
  {
    switch (text.at(i).toAscii()) {
      case '\f':
        Text.clear();
        Text.append(QString());
        xPos = 0;
        break;
      case '\b':
        s = Text.takeLast();
        if (s.size() > 0)
        {
          s.chop(1);
          xPos--;
        }
        Text.append(s);
        break;
      case '\t':
        s = Text.takeLast();
        t = 8 - (s.size() % 8);
        while ((t > 0)  && (s.size() < ConsoleSize.width()))
        {
          s.append(' ');
          t--;
          xPos++;
        }
        Text.append(s);
        if (s.size() >= ConsoleSize.width())
        {
          Text.append(QString());
          xPos = 0;
        }
        break;
      case '\r':
        xPos = 0;
        break;
      case '\n':
        Text.append(QString());
        xPos = 0;
        break;
      default:
        s = Text.takeLast();
        s[xPos++] = text.at(i);
        Text.append(s);
        if (s.size() >= ConsoleSize.width())
        {
          Text.append(QString());
          xPos = 0;
        }
        break;
    }
  }
  while (Text.size() > ConsoleSize.height())
    Text.removeAt(0);
  update();
}

void Console::clear()
{
  Text.clear();
  Text.append(QString());
  xPos = 0;
  update();
}

/*----------------------------------------------------------------------------*/
void Console::keyPressEvent(QKeyEvent *e)
{
  if (e->text().size() > 0)
  {
    for (int i = 0;  i < e->text().size(); i++ )
      emit keyPress(e->text()[i]);
    e->accept();
  }
  else
  {
    e->ignore();
  }
}

void Console::paintEvent(QPaintEvent *)
{
  QPainter paint(this);
  drawFrame(&paint);
  QRect cr = contentsRect();
  cr.adjust(frameWidth(), frameWidth(), -frameWidth(), -frameWidth());

  QFontMetrics fm(fontMetrics());
  int w, h;
  w = fm.maxWidth();
  h = fm.height();
  int x, y;
  y = cr.top() + h;
  for (int i = 0; i < Text.size(); i++)
  {
    x = cr.left();
    for (int j = 0; j < Text.at(i).size(); j++)
    {
      paint.drawText(x, y, Text.at(i).at(j));
      x += w;
    }
    y += h;
  }
  x = cr.left() + xPos * w;
  y = cr.top()  + Text.size() * h - h;
  if (hasFocus())
    paint.fillRect(x + 2, y + h - fm.ascent(), w - 2, h, palette().color(QPalette::Highlight));
  else
    paint.drawRect(x + 2, y + h - fm.ascent(), w - 2, h);
}

/*----------------------------------------------------------------------------*/
void Console::slotShowGeometry()
{
  QString s;
  QRect r;
  r = rect();
  s.append(QString("Rect((%1 : %2) (%3 : %4))").arg(r.left()).arg(r.top()).arg(r.right()).arg(r.bottom()));
  r = frameRect();
  s.append(QString("\nFrameRect((%1 : %2) (%3 : %4))").arg(r.left()).arg(r.top()).arg(r.right()).arg(r.bottom()));
  s.append(QString("\nFrameWidth = %1").arg(frameWidth()));

  QMessageBox::information(this, tr("Console geometry"), s);
}

/*----------------------------------------------------------------------------*/
void Console::copy()
{
  QClipboard *clipboard = QApplication::clipboard();
  clipboard->setText(Text.join("\n"));
}

void Console::paste()
{
  QClipboard *clipboard = QApplication::clipboard();
  QString text = clipboard->text();
  for (int i = 0; i < text.size(); i++)
    emit keyPress(text.at(i));
}

/*----------------------------------------------------------------------------*/
void Console::slotShowFontMetrics()
{
  QChar ch;
  QString s;
  QFontMetrics fm(fontMetrics());
  s.append(QString("%1\n").arg(font().toString()));
  s.append(QString("Line spacing: %1\n").arg(fm.lineSpacing()));
  s.append(QString("Ascent: %1\n").arg(fm.ascent()));
  s.append(QString("Leading: %1\n").arg(fm.leading()));
  s.append(QString("Line width: %1\n").arg(fm.lineWidth()));
  s.append(QString("Min Left Bearing: %1\n").arg(fm.minLeftBearing()));
  s.append(QString("Min Right Bearing: %1\n").arg(fm.minRightBearing()));
  s.append(QString("'M': %1 x %2\n").arg(fm.width("M")).arg(fm.height()));
  s.append(QString("'W': %1 x %2\n").arg(fm.width("W")).arg(fm.height()));
  s.append(QString("'y': %1 x %2\n").arg(fm.width("y")).arg(fm.height()));
  s.append(QString("'D': %1 x %2\n").arg(fm.width("D")).arg(fm.height()));
  ch = QString::fromLocal8Bit("�").at(0);
  s.append(QString("%3: %1 x %2\n").arg(fm.width(ch)).arg(fm.height()).arg(ch));
  ch = QString::fromLocal8Bit("�").at(0);
  s.append(QString("%3: %1 x %2\n").arg(fm.width(ch)).arg(fm.height()).arg(ch));
  ch = QString::fromLocal8Bit("�").at(0);
  s.append(QString("%3: %1 x %2\n").arg(fm.width(ch)).arg(fm.height()).arg(ch));
  ch = QString::fromLocal8Bit("�").at(0);
  s.append(QString("%3: %1 x %2\n").arg(fm.width(ch)).arg(fm.height()).arg(ch));
  ch = QString::fromLocal8Bit("�").at(0);
  s.append(QString("%3: %1 x %2\n").arg(fm.width(ch)).arg(fm.height()).arg(ch));
  ch = QString::fromLocal8Bit("�").at(0);
  s.append(QString("%3: %1 x %2\n").arg(fm.width(ch)).arg(fm.height()).arg(ch));
  ch = QString::fromLocal8Bit("�").at(0);
  s.append(QString("%3: %1 x %2\n").arg(fm.width(ch)).arg(fm.height()).arg(ch));

  QMessageBox::information(this, tr("Font Metrics"), s);
}

/* End of file */
